#!/usr/bin/env python
# -*- coding: UTF-8 -*-

'''Engine for managing the basic 2d tiles in a simple cellular automata'''

from constants import *


class TileManager(object):
    '''A class to help managing tiles'''
    def __init__(self, world_size, tile_size, world_type):
        self.world_size = world_size
        self.tile_size = tile_size
        self.world_type = world_type

        if world_type == WORLD_TYPE_TORUS:
            self.__get_coord_func = self._get_coords_around_torus
            self.__get_pos_func = self._get_pos_in_direction_torus
        elif world_type == WORLD_TYPE_DEAD_AROUND:
            self.__get_coord_func = self._get_coords_dead_around
            self.__get_pos_func = self._get_pos_in_direction_base
        else:
            raise ValueError('Invalid world type')

    def get_coords_around(self, position):
        '''Yields the coordinates around a cell based on the world type'''
        for x, y in self.__get_coord_func(position):
            yield (x, y)

    def get_pos_in_direction(self, position, direction):
        '''Looks up the position of a cell in the given position + direction'''
        return self.__get_pos_func(position, direction)

    def _get_coords_dead_around(self, position):
        '''Yields the coordinates around a position in every direction'''
        x_tile, y_tile = self.tile_size
        orig_x, orig_y = position

        for coord in COORD_LIST:
            mul_x, mul_y = coord

            x = x_tile * mul_x + orig_x
            y = y_tile * mul_y + orig_y

            if x < 0 or y < 0:
                continue

            yield x, y

    def _get_coords_around_torus(self, position):
        '''Yield the coordinates around position, assuming the world is a torus

           Torus means if you go out the top you come out the bottom.
           This wrapping method allows for more things to happen while
           keeping the required space smaller.'''
        world_width, world_height = self.world_size
        tile_width, tile_height = self.tile_size

        minimum_x = 0 - tile_width
        minimum_y = 0 - tile_height

        right_side_x = world_width - tile_width
        up_side_y = world_height - tile_height

        for x, y in self._get_coords_dead_around(position):
            if x == world_width:
                x = 0
            elif x == minimum_x:
                x = right_side_x

            if y == world_height:
                y = 0
            elif y == minimum_y:
                y = up_side_y

            yield x, y

    def get_cell_pos_from_point(self, point_pos):
        '''Transform any coordinates to those of the cell there

        This is relevant for GUI interaction to map any set of (x, y)
        coordinates to the proper (x, y) coordinates of the cell that they
        reside in'''
        tile_x, tile_y = self.tile_size
        point_x, point_y = point_pos

        x = point_x - point_x % tile_x
        y = point_y - point_y % tile_y

        return (x, y)

    def _get_pos_in_direction_base(self, position, direction):
        tile_size = self.tile_size

        x_tile, y_tile = tile_size
        orig_x, orig_y = position

        coord_x, coord_y = COORD_DICT[direction]

        x = x_tile * coord_x + orig_x
        y = y_tile * coord_y + orig_y

        return x, y

    def _get_pos_in_direction_torus(self, position, direction):
        x, y = self._get_pos_in_direction_base(position, direction)

        world_width, world_height = self.world_size
        tile_width, tile_height = self.tile_size

        minimum_x = 0 - tile_width
        minimum_y = 0 - tile_height

        right_side_x = world_width - tile_width
        up_side_y = world_height - tile_height

        if x == world_width:
            x = 0
        elif x == minimum_x:
            x = right_side_x

        if y == world_height:
            y = 0
        elif y == minimum_y:
            y = up_side_y

        return x, y
